9. Do Not Use virtual Function at CTOR & DTOR

파생 클래스가 생성되면,
기본 클래스가 생성자가 먼저 호출되고, 이 후 파생 클래스의 생성자가 호출된다.
class Transaction{
public:
Transaction(); // base class CTOR
virtual void logTransaction() const=0;
};
Transaction::Transaction(void){
// ...
logTransaction(); //
}
class BuyTransaction: public Transaction{
public:
virtual void logTransaction(void) const; //
// ...
};
class SellTransaction: public Transaction{
public:
virtual void logTransaction(void) const; //
}
위와 같이 기본 생성자에서 가상함수를 사용했을 경우,
파생 클래스에서 가상함수가 정의되기 전에 실행하게 된다.

가상함수가 아직 초기화되어 있지 않기 때문에, 의도하지 않게 프로그램 실행됨(C++에서 금지시킴)

소멸될 때,
파생 클래스의 소멸자가 먼저 호출되고, 이후 기본 클래스의 소멸자가 호출된다.
따라서 파생 클래스의 소멸자가 실행된 후, 기본 클래스의 소멸자에서 가상함수를 호출하게 되면,
초기화 되지 않은 함수가 실행되게 된다.
class Transaction{
public:
Transaction(void){ init(); }
virtual void logTransaction() const=0;
private:
void init(void){
logTransaction();
}
};
위의 코드도 위와 같이 동일한 문제를 발생시키지만,
이는 컴파일러에서 에러를 잡지도 못한다.
만일 virtual 함수가 순수 가상함수가 아닌 일반 가상함수인 경우,
생각하지 못한 방향으로 프로그램이 실행된다.

위와 같은 동작을 막기 위해,
logTransaction을 비가상함수로 선언할 수 있다.
class Transaction{
public:
explicit Transaction(const std::string& logInfo);
void logTransaction(const std::string& logInfo) const; //
};
Transaction::Transaction(const std::string& logInfo){
// ...
logTransaction(logInfo);
}
class BuyTransaction: public Transaction{
public:
BuyTransaction(/* parameters */): Transaction(createLogString(/* parameters */)){
// ...
}
// ...
private:
static std::string createLogString(/* parameters */);
};
대신 위와 같이 비가상 함수로 선언해서 사용할 경우
파생 클래스에서 초기화 때, 필요한 정보를 기본 클래스 생성자로 직접 넘겨서 사용한다.